﻿/*
 * Procuder - Consumer Queue
 *
 * Each wait at the same time will receive different result
 *
 */

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Snowdreamist.Collection.ProducerConsumer
{
    public class ProConQueue<T>
    {
        public virtual void Push(T value)
        {
            this.PushOne(value);
        }

        public virtual bool Wait(out T value)
        {
            this._sema.Wait();
            return this.PopOne(out value);
        }

        public virtual bool Wait(TimeSpan time, out T value)
        {
            this._sema.Wait(time);
            return this.PopOne(out value);
        }

        public virtual bool Wait(CancellationToken cancellationToken, out T value)
        {
            this._sema.Wait(cancellationToken);
            return this.PopOne(out value);
        }

        public virtual bool Wait(TimeSpan time, CancellationToken cancellateToken, out T value)
        {
            this._sema.Wait(time, cancellateToken);
            return this.PopOne(out value);
        }

        #region protected

        protected SemaphoreSlim _sema = new SemaphoreSlim(0);

        protected ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();

        protected virtual void PushOne(T value)
        {
            this._queue.Enqueue(value);
        }

        protected virtual bool PopOne(out T value)
        {
            return this._queue.TryDequeue(out value);
        }

        #endregion protected
    }
}